﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _4Gewinnt
{

    class EngineGroup472 : Engine
    {
        //The opponent
        private GameColor op;

        // This board stores the current game situation
        private RedoBoard board = new RedoBoard(4);

        // Implements the MiniMax algorithm
        private MiniMax miniMax;

        //sbr: Diese Variable zählt die Anzahl der bereits gespielten Züge (aktuell nicht genutzt)
        private int anzahlGespielteZuege;

        /// <summary>
        /// Unsere Engine.
        /// Zur Terminologie:
        /// Eine xer-Reihe ist eine Reihe mit x aufeinander folgenden Steinen.
        /// Eine Bedrohung (Threat) ist eine Situation, wo der Gegner eine 3er-Reihe und in der Zukunft (mindestens 2 Züge entfernt) eine 4er-Reihe machen kann. (Natürlich ist es auch eine Bedrohung, wenn der Gegner
        /// in seinem nächsten Zug eine 4er-Reihe machen, aber wir nennen sie nicht so ;-))
        /// </summary>
        /// <param name="me">Wir</param>
        public EngineGroup472(GameColor me)
        {
            //learn own and opponent's color
            this._me = me;
            switch (me)
            {
                case GameColor.Red:
                    op = GameColor.Blue;
                    break;
                case GameColor.Blue:
                    op = GameColor.Red;
                    break;
                case GameColor.Empty:
                    throw new Exception("Wrong initialization color.");
                default:
                    throw new Exception("Wrong initialization color.");
            }
            miniMax = new MiniMax(me, op);
            anzahlGespielteZuege = 0;
        }

        /// <summary>
        /// Makes a move in the current situation
        /// </summary>
        /// <returns>The row number where to set a token</returns>
        public override int makeMove()
        {
            int col = 0;
            //sbr: Sollten wir anfangen, setzen wir den ersten Stein immer in die Mitte
            if (board.isBoardFree())
            {
                col = 3;
                anzahlGespielteZuege++;
                board.moveTo(_me, col);
                return col;
            }

            //sbr: Sollten wir nicht anfangen, setzen wir unseren ersten Stein direkt neben den des Gegners
            if (anzahlGespielteZuege == 1)
            {
                int gegnerCol = 0;
                if (_me == GameColor.Blue)
                {
                    for (int i = 0; i < board.Cols; i++)
                    {
                        if (board.playerAt(5, i) == op)
                        {
                            gegnerCol = i;
                            break;
                        }
                    }
                }
                if (gegnerCol < 4)
                {
                    board.moveTo(_me, gegnerCol + 1);
                    anzahlGespielteZuege++;
                    return gegnerCol + 1;
                }
                else
                {
                    board.moveTo(_me, gegnerCol - 1);
                    anzahlGespielteZuege++;
                    return gegnerCol - 1;
                }
            }
            //sbr: test if we win with next move. If so, move there.
            for (int c = 0; c < board.Cols; c++)
            {
                //test opponent's next moves
                RedoBoard nextMove = board.Clone();
                if (nextMove.isLegalColumn(c))
                {
                    nextMove.moveTo(_me, c);

                    //if op wins when moving to column c, move there 
                    if (nextMove.hasWon(_me))
                    {
                        board.moveTo(_me, c);
                        anzahlGespielteZuege++;
                        return c;
                    }
                }
            }
            //sbr: test if opponent wins with next move. If so, move there.
            for (int c = 0; c < board.Cols; c++)
            {
                //test opponent's next moves
                RedoBoard nextMove = board.Clone();
                if (nextMove.isLegalColumn(c))
                {
                    nextMove.moveTo(op, c);

                    //if op wins when moving to column c, move there 
                    if (nextMove.hasWon(op))
                    {
                        board.moveTo(_me, c);
                        anzahlGespielteZuege++;
                        return c;
                    }
                }
            }

            //sbr: Start der 1. Stufe des MinMax, die verhindert, dass durch unseren Zug der Gegner 4er-Reihen bekommt.
            //Innerhalb der 1. Stufe werden die weiteren Stufen des MinMax-Algos aufgerufen.
            //Diese Tiefe sollte nicht verändert werden, da der Algo sonst nicht mehr funktioniert.
            col = miniMax.minimax(board, 1, anzahlGespielteZuege);
            board.moveTo(_me, col);
            anzahlGespielteZuege++;
            return col;
        }

        /// <summary>
        /// Gets the move of the opponent
        /// </summary>
        /// <param name="c">The column where the opponent has moved</param>
        public override void update(int c)
        {
            board.moveTo(op, c);
            anzahlGespielteZuege++;
        }

        /// <summary>
        /// Called after each engine's turn. null means "nothing to say"
        /// </summary>
        /// <returns>A message a engine can send after each own turn</returns>
        public override string say()
        {
            return "Stefan hat gesetzt. Tobias und Maik bejubeln ihn.";
        }
    }
}
